package com.tn.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.StringUtils;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.Query;
import com.tn.bo.Currency;
import com.tn.bo.POHeader;
import com.tn.bo.POLineItem;
import com.tn.bo.POSplitLineItem;
import com.tn.bo.UnitOfMeasure;
import com.tn.bo.XMLUtil;
import com.tn.service.OfyDataService;




public class PurchaseOrderDAO {
	
	private static final Logger logger = Logger.getLogger(PurchaseOrderDAO.class.getName());

	public POHeader insertPOHeader(POHeader poHeader) throws Exception {
		Objectify txn = OfyDataService.getInstance().beginOfyTransaction();
		txn.put(poHeader);
		if (poHeader.getOrderLineItems() != null) {
			for (POLineItem item : poHeader.getOrderLineItems()) {
				Long uniqueId = getUniqueId(poHeader,item);
				if(uniqueId != null){
					item.setLineItemUniqueId(uniqueId);
				}
				Objectify txn2 = OfyDataService.getInstance()
						.beginOfyTransaction();
				
				txn2.put(item);
				if (item.getLineItemSplits() != null) {
					for (POSplitLineItem split : item.getLineItemSplits()) {
						Objectify txn3 = OfyDataService.getInstance()
								.beginOfyTransaction();
						txn3.put(split);
						OfyDataService.getInstance().commitOfyTransaction(txn3);
					}
				}
				OfyDataService.getInstance().commitOfyTransaction(txn2);
			}
		}
		

		OfyDataService.getInstance().commitOfyTransaction(txn);
		return poHeader;

	}
	
	private Long getUniqueId(POHeader poHeader,POLineItem item2){
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Long uniqueId = null;
		Query<POLineItem> q = ofy.query(POLineItem.class).filter("orderNumber",	poHeader.getOrderNumber());
		for (POLineItem item : q) {
			if(item.getOrderLineItemNumber().equals(item2.getOrderLineItemNumber())){
				 uniqueId = item.getLineItemUniqueId();
				 break;
			 }
		}
		return uniqueId;
	} 
	
	public void updatePOHeader(POHeader poHeader){
		Objectify txn = OfyDataService.getInstance().beginOfyTransaction();
		txn.put(poHeader);
		OfyDataService.getInstance().commitOfyTransaction(txn);
	}

	public POHeader findPOHeaderById(String id) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		POHeader poHeader = ofy.get(new Key<POHeader>(POHeader.class, id));
		return poHeader;

	}

	public List<POHeader> findPOHeaderByOrderCompany(String orderCompany,
			boolean asBuyer) {
		ArrayList<POHeader> retList = new ArrayList<POHeader>();
		
		if (asBuyer) {
			findPOSent(orderCompany, retList);
		} else {
			findPOReceived(orderCompany, retList);
		}
		
		return retList;

	}

	public void findPOReceived(String orderCompany, ArrayList<POHeader> retList) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> q = ofy.query(POHeader.class).filter(
				"orderSupplier", orderCompany);
		filterPurchaseOrders(retList, q);
	}

	private void filterPurchaseOrders(ArrayList<POHeader> retList,
			Query<POHeader> q) {
		//Populate a map first.
		Map<String, List<POHeader>> poMap = new HashMap<String, List<POHeader>>();
		
		
		for (POHeader header : q) {
			String orderNum = header.getOrderNumber();
			List<POHeader> headerList = poMap.get(orderNum);
			if(headerList == null){
				headerList = new ArrayList<POHeader>();
				poMap.put(orderNum, headerList);
			}
			
			if(headerList.isEmpty()){
				headerList.add(header);	
			}else{
				POHeader h2 = headerList.get(0);
				int h2v = Integer.parseInt(h2.getVersionNumber());
				int hv = Integer.parseInt(header.getVersionNumber());
				if(hv > h2v){
					headerList.add(0, header);
				}else{
					headerList.add(header);
				}
			}
		}
		
		Set<Entry<String,List<POHeader>>> entrySet = poMap.entrySet();
		for(Entry<String, List<POHeader>> entry: entrySet){
			POHeader h3 = entry.getValue().get(0);
			// Populate items.
			h3 = populateItemsOnHeader(h3);
			if (!retList.contains(h3)) {
				if(!h3.isCancel()){
				retList.add(h3);
				}
			}
		}
	}

	public void findPOSent(String orderCompany, ArrayList<POHeader> retList) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> q = ofy.query(POHeader.class).filter(
				"orderCompany", orderCompany);
		
		filterPurchaseOrders(retList, q);
	}

	public POHeader populateItemsOnHeader(POHeader poHeader) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		// Find line items for this PO.
		ArrayList<POLineItem> items = new ArrayList<POLineItem>();
		Query<POLineItem> q = ofy.query(POLineItem.class).filter("orderNumber",
				poHeader.getOrderNumber());
		for (POLineItem item : q) {
			if(item.getQuantityInvoiced() == null){
				item.setQuantityInvoiced(new Double(0));
			}
			
			if(StringUtils.isEmpty(item.getUnitCurrencySymbol())){
				item.setUnitCurrencySymbol("USD");
			}
			items.add(item);
		}

		// Find Splits for this line item and attach to Items.
		ArrayList<POSplitLineItem> splits = new ArrayList<POSplitLineItem>();
		Query<POSplitLineItem> q2 = ofy.query(POSplitLineItem.class).filter(
				"orderNumber", poHeader.getOrderNumber());
		for (POSplitLineItem split : q2) {
			splits.add(split);
		}

		for (POSplitLineItem split : splits) {
			for (POLineItem item : items) {
				if (item.getOrderLineItemNumber().equals(
						split.getOrderLineItemNumber())) {
					if (item.getLineItemSplits() == null) {
						item
								.setLineItemSplits(new ArrayList<POSplitLineItem>());
					}

					item.getLineItemSplits().add(split);
				}
			}
		}

		poHeader.setOrderLineItems(items);
		
		//Find History for this PO.
		try{
			poHeader.setPoHistory(this.getPOHistory(poHeader.getOrderNumber()));
			if(poHeader.getPoHistory() != null && poHeader.getPoHistory().size() > 0){
				for(POHeader header2: poHeader.getPoHistory()){
					header2.setOrderLineItems(items);
				}
			}
			
			poHeader.setOrderXml(XMLUtil.getPurchaseOrderXml(poHeader));
		}catch(Exception ex){
			logger.log(Level.SEVERE, ex.toString());

		}

		return poHeader;
	}

	public POHeader getByProperty(String propName, Object propValue) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> q = ofy.query(POHeader.class);
		q.filter(propName, propValue);
		return q.get();
	}
	
	public POHeader getLatestPOHeader(String poNum) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> q = ofy.query(POHeader.class);
		q.filter("orderNumber", poNum);
		q.order("-versionNumber");
		POHeader r = null;
		for(POHeader p: q){
			 r = p;
			 break;
		}
		return r;
	}
	
	public List<POHeader> getPOHistory(String poNum) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> q = ofy.query(POHeader.class);
		q.filter("orderNumber", poNum);
		q.order("-versionNumber");
		List<POHeader> r = new ArrayList<POHeader>();
		for(POHeader p: q){
			p.setOrderXml(XMLUtil.getPurchaseOrderXml(p));
			r.add(p);
		}
		return r;
	}

	public List<POHeader> findAllPOHeaders() {
		ArrayList<POHeader> retList = new ArrayList<POHeader>();
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> q = ofy.query(POHeader.class);
		for (POHeader header : q) {
			retList.add(header);
		}

		return retList;
	}

	/*private String generatePOHeaderId(String prefix) throws Exception {
		return prefix + SequenceGenerator.getNextSequenceValue("PO_SEQ");
	}*/

	public List<UnitOfMeasure> getAllUnitOfMeasures() {
		ArrayList<UnitOfMeasure> retList = new ArrayList<UnitOfMeasure>();
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<UnitOfMeasure> q = ofy.query(UnitOfMeasure.class).order("uniqueName");
		for (UnitOfMeasure u : q) {
			retList.add(u);
		}

		return retList;
	}
	
	public List<Currency> getAllCurrencyCodes() {
		ArrayList<Currency> retList = new ArrayList<Currency>();
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<Currency> q = ofy.query(Currency.class).order("uniqueName");
		for (Currency c : q) {
			retList.add(c);
		}

		return retList;
	}

	public List<POHeader> searchByFilters(Map<String, Object> filters) {
		ArrayList<POHeader> l = new ArrayList<POHeader>();
		try {
			Objectify ofy = OfyDataService.getInstance().getOfyService();
			Query<POHeader> q = ofy.query(POHeader.class);
			Set<Entry<String,Object>> entrySet = filters.entrySet();
			for(Entry<String,Object> entry: entrySet){
				q = q.filter(entry.getKey(), entry.getValue());
			}
			
			filterPurchaseOrders(l,q);
		} catch (Exception e) {
			logger.log(Level.SEVERE,"Error during PO Search.", e);
		}
		return l;
	}

}
